package ru.tennisworld.user.controllers;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import ru.tennisworld.user.enums.ErrorResponseCode;
import ru.tennisworld.user.enums.ValidationErrorEnum;
import ru.tennisworld.user.exceptions.TennisUserServiceException;
import ru.tennisworld.user.exceptions.TennisUserValidationException;
import ru.tennisworld.user.responses.ErrorResponse;

import java.util.Map;
import java.util.Optional;

@ControllerAdvice
public class ErrorHandler {

    private static final Logger LOG = LoggerFactory.getLogger(ErrorHandler.class);

    @ExceptionHandler
    public <E extends TennisUserServiceException> ResponseEntity<ErrorResponse<String>> handleException(E exception) {
        LOG.info(exception.getMessage(), LOG.isDebugEnabled() ? exception : null);
        final ErrorResponse<String> errorResponse = createErrorResponse(exception.getCode(), exception);
        final HttpStatus httpStatus = Optional.of(exception.getHttpStatus())
                .map(HttpStatus::resolve)
                .orElse(HttpStatus.INTERNAL_SERVER_ERROR);
        return new ResponseEntity<>(errorResponse, httpStatus);
    }

    @ExceptionHandler
    public ResponseEntity<ErrorResponse<String>> handleException(TennisUserValidationException exception) {
        final ResponseEntity<ErrorResponse<String>> response = handleException((TennisUserServiceException) exception);
        ErrorResponse<String> body = response.getBody();
        if (exception.getValidationResult() != null && body != null) {
            for (Map.Entry<ValidationErrorEnum, String> entry : exception.getValidationResult().getErrorsList().entrySet()) {
                if (entry.getValue() != null) {
                    body.getParams().put(entry.getKey().getPath(), entry.getValue());
                } else {
                    body.getParams().put(entry.getKey().getPath(), entry.getKey().getDefaultMessage());
                }
            }
        }
        return response;
    }

    private static ErrorResponse<String> createErrorResponse(ErrorResponseCode code, Exception exception) {
        if (code == null) {
            return null;
        } else if (LOG.isDebugEnabled()) {
            return new ErrorResponse<>(code.getErrorCode(), exception.getMessage());
        } else {
            return new ErrorResponse<>(code.getErrorCode());
        }
    }
}
